package cn.jiangjiesheng.bootstrap.database;

import cn.jiangjiesheng.bootstrap.database.properties.MyBatisConfig;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
import cn.jiangjiesheng.bootstrap.database.properties.MyDataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.lang.Nullable;

import javax.sql.DataSource;
import java.util.Map;

/**
 * Created by dev@jiangjiesheng.cn on 2021/9/2  <br/>
 *
 * @author dev@jiangjiesheng.cn
 */
@ConditionalOnClass(DruidDataSource.class)
//这里似乎必须开启第一个数据库，才会做相应的初始化
@ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.one.enabled'))}")
@Configuration
@Slf4j
@AutoConfigureBefore(PageHelperAutoConfiguration.class)
public class MyDataSourceAutoConfiguration {

    private Resource mybatisConfig = new ClassPathResource("config/mybatis-config.xml");

    @Primary
    @Bean(value = {"dataSourceOne"})
    @ConditionalOnMissingBean(name = "dataSourceOne")
    @ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.one.enabled'))}")
    public DataSource dataSourceOne(MyDataSourceProperties properties, Environment env) {
        try {
            Map<?, ?> map = BeanMap.create(properties.getDatasource()
                    .get(env.getProperty("spring.application.name"))
                    .get("one"));
            return DruidDataSourceFactory.createDataSource(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Bean(value = "dataSourceTwo")
    @Nullable
    @ConditionalOnMissingBean(name = "dataSourceTwo")
    @ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.two.enabled'))}")
    public DataSource dataSourceTwo(MyDataSourceProperties properties, Environment env) {
        try {
            Map<?, ?> map = BeanMap.create(properties.getDatasource()
                    .get(env.getProperty("spring.application.name"))
                    .get("two"));
            return DruidDataSourceFactory.createDataSource(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Nullable
    @Bean(value = "dataSourceThree")
    @ConditionalOnMissingBean(name = "dataSourceThree")
    @ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.three.enabled'))}")
    public DataSource dataSourceThree(MyDataSourceProperties properties, Environment env) {
        try {
            Map<?, ?> map = BeanMap.create(properties.getDatasource()
                    .get(env.getProperty("spring.application.name"))
                    .get("three"));
            return DruidDataSourceFactory.createDataSource(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //如果 这里注入不进去，要看下 MyJdbcTemplateAutoConfiguration
    @Nullable
    @Bean(value = "dataSourceFour")
    @ConditionalOnMissingBean(name = "dataSourceFour")
    @ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.four.enabled'))}")
    public DataSource dataSourceFour(MyDataSourceProperties properties, Environment env) {
        try {
            Map<?, ?> map = BeanMap.create(properties.getDatasource()
                    .get(env.getProperty("spring.application.name"))
                    .get("four"));
            return DruidDataSourceFactory.createDataSource(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //如果 这里注入不进去，要看下 MyJdbcTemplateAutoConfiguration
    @Nullable
    @Bean(value = "dataSourceFive")
    @ConditionalOnMissingBean(name = "dataSourceFive")
    @ConditionalOnExpression("#{'true'.equals(environment.getProperty('spring.datasource.'+environment.getProperty('spring.application.name')+'.five.enabled'))}")
    public DataSource dataSourceFive(MyDataSourceProperties properties, Environment env) {
        try {
            Map<?, ?> map = BeanMap.create(properties.getDatasource()
                    .get(env.getProperty("spring.application.name"))
                    .get("five"));
            return DruidDataSourceFactory.createDataSource(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Primary
    @Bean(name = "sqlSessionFactoryOne")
    @ConditionalOnBean(name = "dataSourceOne")
    public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceOne") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        if (mybatisConfig.exists()) {
            bean.setConfigLocation(mybatisConfig);
        } else {
            bean.setConfiguration(MyBatisConfig.getConfig());
        }
        Resource[] resources;
        resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/one/*.xml");
        if (resources.length > 0) {
            log.info("using mapper in mapp**/one/*.xml");
            bean.setMapperLocations(resources);
        } else {
            log.info("using mapper in mapp**/**/*.xml");
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/**/*.xml"));
        }
        return bean.getObject();
    }

    @Bean(name = "sqlSessionFactoryTwo")
    @ConditionalOnBean(name = "dataSourceTwo")
    @ConditionalOnMissingBean(name = "sqlSessionFactoryTwo")
    public SqlSessionFactory sqlSessionFactoryTwo(@Qualifier("dataSourceTwo") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        if (mybatisConfig.exists()) {
            bean.setConfigLocation(mybatisConfig);
        } else {
            bean.setConfiguration(MyBatisConfig.getConfig());
        }
        Resource[] resources;
        resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/two/*.xml");
        if (resources.length > 0) {
            log.info("using mapper in mapp**/two/*.xml");
            bean.setMapperLocations(resources);
        } else {
            log.info("using mapper in mapp**/**/*.xml");
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/**/*.xml"));
        }
        return bean.getObject();
    }

    @ConditionalOnMissingBean(name = "sqlSessionFactoryThree")
    @Bean(name = "sqlSessionFactoryThree")
    @ConditionalOnBean(name = "dataSourceThree")
    public SqlSessionFactory sqlSessionFactoryThree(@Qualifier("dataSourceThree") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        if (mybatisConfig.exists()) {
            bean.setConfigLocation(mybatisConfig);
        } else {
            bean.setConfiguration(MyBatisConfig.getConfig());
        }
        Resource[] resources;
        resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/three/*.xml");
        if (resources.length > 0) {
            log.info("using mapper in mapp**/three/*.xml");
            bean.setMapperLocations(resources);
        } else {
            log.info("using mapper in mapp**/**/*.xml");
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/**/*.xml"));
        }
        return bean.getObject();
    }

    //如果 这里注入不进去，要看下 MyJdbcTemplateAutoConfiguration
    @ConditionalOnMissingBean(name = "sqlSessionFactoryFour")
    @Bean(name = "sqlSessionFactoryFour")
    @ConditionalOnBean(name = "dataSourceFour")
    public SqlSessionFactory sqlSessionFactoryFour(@Qualifier("dataSourceFour") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        if (mybatisConfig.exists()) {
            bean.setConfigLocation(mybatisConfig);
        } else {
            bean.setConfiguration(MyBatisConfig.getConfig());
        }
        Resource[] resources;
        resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/four/*.xml");
        if (resources.length > 0) {
            log.info("using mapper in mapp**/four/*.xml");
            bean.setMapperLocations(resources);
        } else {
            log.info("using mapper in mapp**/**/*.xml");
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/**/*.xml"));
        }
        return bean.getObject();
    }


    //如果 这里注入不进去，要看下 MyJdbcTemplateAutoConfiguration
    @ConditionalOnMissingBean(name = "sqlSessionFactoryFive")
    @Bean(name = "sqlSessionFactoryFive")
    @ConditionalOnBean(name = "dataSourceFive")
    public SqlSessionFactory sqlSessionFactoryFive(@Qualifier("dataSourceFive") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        if (mybatisConfig.exists()) {
            bean.setConfigLocation(mybatisConfig);
        } else {
            bean.setConfiguration(MyBatisConfig.getConfig());
        }
        Resource[] resources;
        resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/five/*.xml");
        if (resources.length > 0) {
            log.info("using mapper in mapp**/five/*.xml");
            bean.setMapperLocations(resources);
        } else {
            log.info("using mapper in mapp**/**/*.xml");
            bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapp*/**/*.xml"));
        }
        return bean.getObject();
    }
}
